| @@ -0,0 +1,38 @@ | ||
| 1 | +# -*- coding: utf-8 -*- | |
| 2 | + | |
| 3 | +from __future__ import division | |
| 4 | + | |
| 5 | +from paginator import pagination | |
| 6 | + | |
| 7 | +from django.db import transaction | |
| 8 | +from django.db.models import Q | |
| 9 | +from django_logit import logit | |
| 10 | + | |
| 11 | +from kodo.decorators import check_admin | |
| 12 | +from mch.models import AdministratorInfo, ConsumeShotUnbindingInfo | |
| 13 | + | |
| 14 | + | |
| 15 | +@logit | |
| 16 | +@check_admin | |
| 17 | +def consumer_shot_unbinding_list(request, administrator): | |
| 18 | +    start_time = request.POST.get('start_time', '') | |
| 19 | +    end_time = request.POST.get('end_time', '') | |
| 20 | +    query = request.POST.get('query', '') | |
| 21 | + | |
| 22 | + unbindings = ConsumeShotUnbindingInfo.objects.filter(Q(phone__icontains=query) | Q(sn__icontains=query), status=True) | |
| 23 | + | |
| 24 | + if start_time and end_time: | |
| 25 | + start_time = tc.string_to_utc_datetime(start_time, format='%Y%m%d') | |
| 26 | + end_time = tc.string_to_utc_datetime(end_time + ' 23:59:59', format='%Y%m%d %H:%M:%S') | |
| 27 | + unbindings = unbindings.filter(created_at__range=(start_time, end_time)) | |
| 28 | + | |
| 29 | + count = unbindings.count() | |
| 30 | + | |
| 31 | + unbindings, left = pagination(unbindings, page, num) | |
| 32 | + unbindings = [unbinding.admindata for unbinding in unbindings] | |
| 33 | + | |
| 34 | +    return response(200, 'Get Cosumer Shot Unbinding List Success', u'用户列表获取成功', data={ | |
| 35 | + 'unbinding': userinfos, | |
| 36 | + 'count': count, | |
| 37 | + 'left': left | |
| 38 | + }) | 
| @@ -19,7 +19,7 @@ from coupon.models import CouponInfo, UserCouponInfo | ||
| 19 | 19 | from integral.models import SaleclerkSubmitLogInfo | 
| 20 | 20 | from logs.models import AdministratorLoginLogInfo, MchInfoEncryptLogInfo | 
| 21 | 21 | from mch.models import (ActivityInfo, AdministratorInfo, BrandInfo, ConsumeInfoSubmitLogInfo, DistributorInfo, | 
| 22 | - LatestAppInfo, LatestAppScreenInfo, ModelInfo, OperatorInfo) | |
| 22 | + LatestAppInfo, LatestAppScreenInfo, ModelInfo, OperatorInfo, ConsumeShotUnbindingInfo) | |
| 23 | 23 | from statistic.models import ConsumeModelSaleStatisticInfo, ConsumeSaleStatisticInfo, ConsumeUserStatisticInfo | 
| 24 | 24 | from utils.error.errno_utils import (AdministratorStatusCode, OperatorStatusCode, ProductBrandStatusCode, | 
| 25 | 25 | ProductModelStatusCode, UserStatusCode) | 
| @@ -521,3 +521,31 @@ def consumer_model_list(request): | ||
| 521 | 521 |      return response(200, 'Get Model List Success', u'获取型号列表成功', { | 
| 522 | 522 | 'models': models, | 
| 523 | 523 | }) | 
| 524 | + | |
| 525 | + | |
| 526 | +@logit(res=True) | |
| 527 | +@transaction.atomic | |
| 528 | +def consumer_shot_unbinding(request): | |
| 529 | +    user_id = request.POST.get('user_id', '') | |
| 530 | +    submit_pk = request.POST.get('id', '') | |
| 531 | +    submit_at = request.POST.get('created_at', '') | |
| 532 | +    model_id = request.POST.get('model_id', '') | |
| 533 | +    sn = request.POST.get('serialNo', '') | |
| 534 | +    reason = request.POST.get('reason', '') | |
| 535 | + | |
| 536 | + # 校验用户是否存在 | |
| 537 | + try: | |
| 538 | + user = UserInfo.objects.get(user_id=user_id) | |
| 539 | + except UserInfo.DoesNotExist: | |
| 540 | + return response(UserStatusCode.USER_NOT_FOUND) | |
| 541 | + | |
| 542 | +    ConsumeShotUnbindingInfo.objects.update_or_create(user_id=user_id, submit_pk=submit_pk, defaults={ | |
| 543 | + 'model_id': model_id, | |
| 544 | + 'sn': sn, | |
| 545 | + 'submit_at': submit_at, | |
| 546 | + 'reason': reason, | |
| 547 | + }) | |
| 548 | + | |
| 549 | + return response(200, 'Consume Shot Unbinding Success', u'消费者镜头解绑成功') | |
| 550 | + | |
| 551 | + | 
| @@ -6,7 +6,7 @@ from django_file_upload import views as file_views | ||
| 6 | 6 | from api import (admin_views, clerk_views, complement_views, distributor_views, encrypt_views, express_views, log_views, | 
| 7 | 7 | maintenance_point_views, maintenance_views, mch_views, member_views, model_views, operator_views, | 
| 8 | 8 | refresh_views, sr_views, staff_views, tenancy_admin_views, tenancy_views, tencentcloud_views, wx_views, | 
| 9 | - wxa_views) | |
| 9 | + wxa_views, consumer_admin_view) | |
| 10 | 10 | from miniapp import qy_views | 
| 11 | 11 | from miniapp import views as mini_views | 
| 12 | 12 | from page import oauth_views, sale_views, screen_views | 
| @@ -58,7 +58,8 @@ urlpatterns += [ | ||
| 58 | 58 | url(r'^consumer_phone$', mch_views.consumer_phone_api, name='consumer_phone_api'), | 
| 59 | 59 | url(r'^consumer_info$', mch_views.consumer_info_api, name='consumer_info_api'), | 
| 60 | 60 | url(r'^consumer_snlist$', mch_views.consumer_snlist_api, name='consumer_snlist_api'), | 
| 61 | - url(r'^consumer_model_list$', mch_views.consumer_model_list, name='consumer_model_list') | |
| 61 | + url(r'^consumer_model_list$', mch_views.consumer_model_list, name='consumer_model_list'), | |
| 62 | + url(r'^consumer/shot/unbinding$', mch_views.consumer_shot_unbinding, name='consumer_shot_unbinding'), | |
| 62 | 63 | ] | 
| 63 | 64 |  | 
| 64 | 65 | urlpatterns += [ | 
| @@ -159,6 +160,7 @@ urlpatterns += [ | ||
| 159 | 160 | url(r'^admin/record/sale$', admin_views.record_sale, name='record_sale'), | 
| 160 | 161 | url(r'^admin/record/sale/batch$', admin_views.record_sale_batch, name='record_sale_batch'), | 
| 161 | 162 | url(r'^admin/record/warehouse$', admin_views.record_warehouse, name='record_warehouse'), | 
| 163 | + url(r'^admin/consumer/shot/unbinding/list$', consumer_admin_view.consumer_shot_unbinding_list, name='consumer_shot_unbinding_list'), | |
| 162 | 164 |  | 
| 163 | 165 | url(r'^admin/list/model$', admin_views.model_list, name='model_list'), | 
| 164 | 166 | url(r'^admin/list/distributor$', admin_views.distributor_list, name='distributor_list'), | 
| @@ -0,0 +1,37 @@ | ||
| 1 | +# -*- coding: utf-8 -*- | |
| 2 | + | |
| 3 | +# Generated by Django 3.2.6 on 2023-03-01 07:25 | |
| 4 | + | |
| 5 | +from django.db import migrations, models | |
| 6 | + | |
| 7 | + | |
| 8 | +class Migration(migrations.Migration): | |
| 9 | + | |
| 10 | + dependencies = [ | |
| 11 | +        ('mch', '0066_auto_20230208_1344'), | |
| 12 | + ] | |
| 13 | + | |
| 14 | + operations = [ | |
| 15 | + migrations.CreateModel( | |
| 16 | + name='ConsumeShotUnbindingInfo', | |
| 17 | + fields=[ | |
| 18 | +                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | |
| 19 | +                ('status', models.BooleanField(default=True, help_text='Status', verbose_name='status')), | |
| 20 | +                ('created_at', models.DateTimeField(auto_now_add=True, help_text='Create Time', verbose_name='created_at')), | |
| 21 | +                ('updated_at', models.DateTimeField(auto_now=True, help_text='Update Time', verbose_name='updated_at')), | |
| 22 | +                ('brand_id', models.CharField(blank=True, db_index=True, help_text='品牌唯一标识', max_length=32, null=True, verbose_name='brand_id')), | |
| 23 | +                ('brand_name', models.CharField(blank=True, help_text='品牌名称', max_length=255, null=True, verbose_name='brand_name')), | |
| 24 | +                ('user_id', models.CharField(blank=True, db_index=True, help_text='用户唯一标识', max_length=32, null=True, verbose_name='user_id')), | |
| 25 | +                ('submit_pk', models.IntegerField(blank=True, default=0, help_text='消费者提交ID', null=True, verbose_name='submit_pk')), | |
| 26 | +                ('submit_at', models.DateTimeField(blank=True, help_text='消费者提交时间', null=True, verbose_name='submit_at')), | |
| 27 | +                ('model_id', models.CharField(blank=True, db_index=True, help_text='型号唯一标识', max_length=32, null=True, verbose_name='model_id')), | |
| 28 | +                ('sn', models.CharField(blank=True, db_index=True, help_text='序列号', max_length=16, null=True, verbose_name='sn')), | |
| 29 | +                ('reason', models.CharField(blank=True, db_index=True, help_text='解绑理由', max_length=256, null=True, verbose_name='model_id')), | |
| 30 | + ], | |
| 31 | +            options={ | |
| 32 | + 'verbose_name': '消费者镜头解绑记录', | |
| 33 | + 'verbose_name_plural': '消费者镜头解绑记录', | |
| 34 | +                'unique_together': {('user_id', 'submit_pk')}, | |
| 35 | + }, | |
| 36 | + ), | |
| 37 | + ] | 
| @@ -0,0 +1,20 @@ | ||
| 1 | +# -*- coding: utf-8 -*- | |
| 2 | + | |
| 3 | +# Generated by Django 3.2.6 on 2023-03-01 10:21 | |
| 4 | + | |
| 5 | +from django.db import migrations, models | |
| 6 | + | |
| 7 | + | |
| 8 | +class Migration(migrations.Migration): | |
| 9 | + | |
| 10 | + dependencies = [ | |
| 11 | +        ('mch', '0067_consumeshotunbindinginfo'), | |
| 12 | + ] | |
| 13 | + | |
| 14 | + operations = [ | |
| 15 | + migrations.AlterField( | |
| 16 | + model_name='consumeshotunbindinginfo', | |
| 17 | + name='reason', | |
| 18 | + field=models.CharField(blank=True, db_index=True, help_text='解绑理由', max_length=256, null=True, verbose_name='reason'), | |
| 19 | + ), | |
| 20 | + ] | 
| @@ -9,6 +9,7 @@ from jsonfield import JSONField | ||
| 9 | 9 | from shortuuidfield import ShortUUIDField | 
| 10 | 10 | from TimeConvert import TimeConvert as tc | 
| 11 | 11 |  | 
| 12 | +from kodo.basemodels import BrandInfoMixin | |
| 12 | 13 | from coupon.models import CouponInfo | 
| 13 | 14 |  | 
| 14 | 15 |  | 
| @@ -770,6 +771,7 @@ class ConsumeInfoSubmitLogInfo(BaseModelMixin): | ||
| 770 | 771 | 'final_coupon_info': act.coupon_info(created_at=self.created_at) if act else self.coupon_info, | 
| 771 | 772 | 'has_used': self.has_used, | 
| 772 | 773 | 'used_at': self.used_at, | 
| 774 | + 'created_at': tc.local_string(utc_dt=self.created_at, format='%Y-%m-%d %H:%M'), | |
| 773 | 775 | } | 
| 774 | 776 |  | 
| 775 | 777 | @property | 
| @@ -800,6 +802,44 @@ class ConsumeInfoSubmitLogInfo(BaseModelMixin): | ||
| 800 | 802 | } | 
| 801 | 803 |  | 
| 802 | 804 |  | 
| 805 | +class ConsumeShotUnbindingInfo(BaseModelMixin, BrandInfoMixin): | |
| 806 | + user_id = models.CharField(_(u'user_id'), max_length=32, blank=True, null=True, help_text=u'用户唯一标识', db_index=True) | |
| 807 | + submit_pk = models.IntegerField(_(u'submit_pk'), default=0, blank=True, null=True, help_text=u'消费者提交ID') | |
| 808 | + submit_at = models.DateTimeField(_(u'submit_at'), blank=True, null=True, help_text=u'消费者提交时间') | |
| 809 | + model_id = models.CharField(_(u'model_id'), max_length=32, blank=True, null=True, help_text=u'型号唯一标识', db_index=True) | |
| 810 | + sn = models.CharField(_(u'sn'), max_length=16, blank=True, null=True, help_text=u'序列号', db_index=True) | |
| 811 | + reason = models.CharField(_(u'reason'), max_length=256, blank=True, null=True, help_text=u'解绑理由', db_index=True) | |
| 812 | + | |
| 813 | + class Meta: | |
| 814 | + verbose_name = _(u'消费者镜头解绑记录') | |
| 815 | + verbose_name_plural = _(u'消费者镜头解绑记录') | |
| 816 | + | |
| 817 | + unique_together = ( | |
| 818 | +            ('user_id', 'submit_pk'), | |
| 819 | + ) | |
| 820 | + | |
| 821 | + def __unicode__(self): | |
| 822 | + return '%d' % self.pk | |
| 823 | + | |
| 824 | + @property | |
| 825 | + def admindata(self): | |
| 826 | + from account.models import UserInfo | |
| 827 | + | |
| 828 | + info = ModelInfo.objects.get(model_id=self.model_id).fulldata | |
| 829 | + user = UserInfo.objects.get(user_id=self.user_id) | |
| 830 | + | |
| 831 | +        return { | |
| 832 | + 'user_id': self.user_id, | |
| 833 | + 'phone': user.phone, | |
| 834 | + 'model_info': model_info, | |
| 835 | + 'sn': self.sn, | |
| 836 | + 'reason': self.reason, | |
| 837 | + 'submit_pk': self.submit_pk, | |
| 838 | + 'submit_at': self.submit_at, | |
| 839 | + 'created_at': self.created_at, | |
| 840 | + } | |
| 841 | + | |
| 842 | + | |
| 803 | 843 | class ActivityInfo(BaseModelMixin): | 
| 804 | 844 | FIXED_EXPIRED_TIME = 0 | 
| 805 | 845 | CHANGED_EXPIRED_TIME = 1 |